﻿using System;
using System.IO;
using System.Net;
using System.Xml;

namespace RealDolmen.Helpers
{
    public class SoapService
    {
        #region Properties
        private string url;

        public string Url
        {
            get { return url; }
            set { url = value; }
        }

        #endregion // Properties

        #region Constructors
        public SoapService() { }
        public SoapService(string url)
        {
            Url = url;
        }
        
        #endregion // Constructors

        #region Business Method
        public void Invoke(string soapAction, object[] parameters)
        {
            if (!string.IsNullOrEmpty(Url))
            {
                SoapAction mySoapAction = new SoapAction(soapAction);
                XmlDocument xmlDoc = GenerateSoapEnvelope(mySoapAction, parameters);

                string response = string.Empty;
                try
                {
                    do
                    {
                        // Create the request & headers
                        HttpWebRequest req = (HttpWebRequest)WebRequest.Create(Url);
                        req.Headers.Add("SOAPAction", mySoapAction.ToString());
                        req.ContentType = "text/xml;charset=\"utf-8\"";
                        req.Accept = "text/xml";
                        req.Method = "POST";
                        req.Timeout = 30000;

                        // Add the envelope
                        Stream stm = req.GetRequestStream();
                        xmlDoc.Save(stm);
                        stm.Close();

                        // Go for the response
                        WebResponse resp = req.GetResponse();
                        stm = resp.GetResponseStream();
                        using (StreamReader sr = new StreamReader(stm))
                        {
                            response = sr.ReadToEnd();
                        }

                        System.Diagnostics.Trace.TraceInformation(response);
                    } while (string.IsNullOrEmpty(response) || HasRefreshForUrl(response, url));
                }
                catch (Exception ex)
                {
                    System.Diagnostics.Trace.TraceError(ex.ToString());
                }

            }
        }
        #endregion // Business Method

        #region Helpers
        private static bool HasRefreshForUrl(string response, string url)
        {
            response = response.ToLower();
            url = url.ToLower();

            return response.Contains("refresh") && response.Contains(url);
        }
        #endregion // Helpers

        #region Generate Soap Envelope
        protected readonly static string SOAPTEMPLATE = "<?xml version=\"1.0\" encoding=\"utf-8\"?><soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\"><soap:Body /></soap:Envelope>";

        public static XmlDocument GenerateSoapEnvelope(SoapAction soapAction, object[] parameters)
        {
            XmlDocument xmlDoc = new XmlDocument();
            xmlDoc.LoadXml(SOAPTEMPLATE);

            XmlElement methodElement = xmlDoc.CreateElement(soapAction.MethodName, soapAction.Namespace);

            foreach (object parameter in parameters)
            {
                string strParameter = parameter.ToString();
                int idx = strParameter.IndexOf(':');
                if (idx > 0)
                {
                    string name = strParameter.Substring(0, idx).Trim();
                    string value = strParameter.Substring(idx + 1).Trim();

                    XmlElement parameterElement = xmlDoc.CreateElement(name, soapAction.Namespace);
                    parameterElement.InnerText = value;

                    methodElement.AppendChild(parameterElement);
                }
            }

            XmlNode bodyelement = xmlDoc.SelectSingleNode("soap:Envelope/soap:Body", NamespaceManager);
            bodyelement.AppendChild(methodElement);
            return xmlDoc;
        }
        private static XmlNamespaceManager m_nsmgr;
        protected static XmlNamespaceManager NamespaceManager
        {
            get
            {
                if (m_nsmgr == null)
                {
                    XmlNameTable nameTable = new NameTable();
                    XmlNamespaceManager manager = new XmlNamespaceManager(nameTable);
                    manager.AddNamespace("soap", "http://schemas.xmlsoap.org/soap/envelope/");
                    m_nsmgr = manager;
                }
                return m_nsmgr;
            }
        }
        #endregion // Generate Soap Envelope
    }

    #region SoapAction
    public class SoapAction
    {
        public string MethodName;

        public string Namespace;

        public SoapAction(string soapAction)
        {
            this.soapAction = soapAction;

            int idx = soapAction.LastIndexOf('/') + 1;

            MethodName = soapAction.Substring(idx);
            Namespace = soapAction.Substring(0, idx);
        }

        private string soapAction;
        public override string ToString()
        {
            return soapAction;
        }
    } 
    #endregion // SoapAction
}